package com.gmrz.uaf.servlet.v1.handler;

import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.common.UAFException;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.processor.UAFDeviceProcessor;
import com.gmrz.uaf.protocol.v1.processor.exception.UAFErrorCode;
import com.gmrz.uaf.protocol.v1.schema.RegistrationRequest;
import com.gmrz.uaf.server.ServerContext;
import com.gmrz.uaf.servlet.v1.request.DeviceSupportContext;
import com.gmrz.uaf.servlet.v1.request.ReceiveReqPayload;
import com.gmrz.uaf.servlet.v1.response.FidoRespPayload;
import com.gmrz.uaf.servlet.v1.validation.PayloadValidationException;
import com.gmrz.uaf.servlet.v1.validation.RestValidator;
import com.gmrz.util.Convert;
import com.gmrz.util.Strings;
import com.gmrz.util.UUIDGenerator;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by chentaikun on 16/12/19.
 */
public class UAFDeviceHandler extends UAFBaseHandler{

    private static final Logger LOG = LogManager.getLogger(UAFDeviceHandler.class);


    /**
     * {
     *     "context":{"transNo":"","authType":"00","appID","001"}
     * }
     * @param request
     * {
     *     "statusCode":1000,
     *     "description":"xxxxxx",
     *     "uafRequest":[
     *     "[{\"header\":{....},\"policy\":{.....}}]",
     *     "[{\"header\":{....},\"policy\":{.....}}]"
     *     ]
     * }
     */
    public String deviceSupport(String request){

        LOG.info("[/device/support][begin]");
        ServerContext.getServerContext().getFidoLog().setRequest(request);
        FidoRespPayload<List<String>> respPayload10 = new FidoRespPayload<List<String>>();
        FidoRespPayload<String> respPayload11 = new FidoRespPayload<String>();
        String response = null;

        try {

            Gson gson = UAFSchemaBuilder.getGson();
            Type reqType = new TypeToken<ReceiveReqPayload<DeviceSupportContext>>() {  }
                    .getType();
            // 将请求串转为对象
            ReceiveReqPayload<DeviceSupportContext> reqPayload =gson.fromJson(request, reqType);

            ServerContext.getServerContext().setBase64(reqPayload.getContext().isBase64());
            // 记录日志
            logRequest(request,reqPayload.getContext().getTransNo(),reqPayload.getContext().getUserName(),
                    reqPayload.getContext().getAppID(), Strings.listToString(reqPayload.getContext().getAuthType()),null, Constants.Method.DEVICE_SUPPORT);
            // 校验状态
            checkUafRegStatus();
            //验证厂商白名单和设备黑名单
            validateDevice(reqPayload.getContext().getDevices(),reqPayload.getContext().getAppID());
            // 校验请求参数
            validate(reqPayload);
            UAFDeviceProcessor processor = GuiceUtil.getProcessorInjector().
                    getInstance(UAFDeviceProcessor.class);
            DeviceSupportContext context = reqPayload.getContext();
            String userID = UUIDGenerator.generateID();
            List<String> authTypes = context.getAuthType();

            List<String> uafRequestList = new ArrayList<String>();
            for(String authType:authTypes){
                if(Constants.AuthType.isAuthType(authType)) {
                    try {
                        // 能力支持查询业务处理
                        List<RegistrationRequest> requests = processor.support(userID, authType, context.getAppID(),null);
                        // 查看是否支持当前手机类型、手机名称
                        requests = checkVendorAccept(requests,reqPayload.getContext().getDevices());
                        if("1.1".equals(this.getServerConfig().getUafDeviceSupportVersion())){
                            String s = gson.toJson(requests);
                            Map<String, Object> map = new HashMap<String, Object>();
                            map.put("result", requests);
                            map.put("authType", authType);
                            uafRequestList.add(gson.toJson(map));
                        }else {
                            uafRequestList.add(gson.toJson(requests));
                        }
                    } catch (Exception e) {
                        LOG.error(e);
                    }
                }else {
                    throw new UAFException(UAFErrorCode.PROTOCOL_AUTH_TYPE_FAIL);
                }
            }

            if("1.1".equals(this.getServerConfig().getUafDeviceSupportVersion())) {
                respPayload11.setStatusCode(1200);
                respPayload11.setDescription("OK");
                if(ServerContext.getServerContext().isBase64()){
                    respPayload11.setUafRequest(Convert.toBase64(gson.toJson(uafRequestList).getBytes()));
                }else {
                    respPayload11.setUafRequest(gson.toJson(uafRequestList));
                }
                return gson.toJson(respPayload11);
            }else {
                respPayload10.setStatusCode(1200);
                respPayload10.setDescription("OK");
                if(ServerContext.getServerContext().isBase64()){
                    List<String> list = new ArrayList<String>();
                    for(String str : uafRequestList){
                        list.add(Convert.toBase64(str.getBytes()));
                    }
                    respPayload10.setUafRequest(list);
                }else {
                    respPayload10.setUafRequest(uafRequestList);
                }
                return gson.toJson(respPayload10);
            }
        } catch (Exception ex) {
            LOG.error(ex);
            response = buildFidoRespFromException(respPayload10, ex);
        }
        LOG.info("[/device/support][end]");
        return response;
    }

    private void validate(ReceiveReqPayload<DeviceSupportContext> reqPayload)
            throws PayloadValidationException
    {
        if ((reqPayload == null) || (reqPayload.getContext() == null)) {
            throw new PayloadValidationException("context", RestValidator.VALIDATION_ERROR.EMPTY);
        }
        List<String> authType = reqPayload.getContext().getAuthType();
        if(null == authType || authType.isEmpty()){
            throw new PayloadValidationException("authType", RestValidator.VALIDATION_ERROR.EMPTY);
        }
        for(String a:authType){
            RestValidator.validate("authType", a);
        }
        String appID = reqPayload.getContext().getAppID();
        RestValidator.validate("appID", appID);
        RestValidator.validate("transNo",reqPayload.getContext().getTransNo());
    }
}


